<script setup lang="ts">
import {computed, nextTick, onMounted, onUnmounted, reactive, ref, watch, render, h, shallowRef} from 'vue'
import { useDeviceListApi, useDeviceStatusInfoApi } from '@/api/gps/device'
import { cloneDeep } from 'lodash'
import { ElTree } from 'element-plus'
import { Refresh, More, Search, Setting, Fold } from '@element-plus/icons-vue'
import SendCmd from '@/views/dashboard/sendCmd.vue'
import { gpsbus } from '@/utils/gps/event'
import { computeSubTitle, jt1078AvsetAnalysis } from '@/utils/gps/format'
import { useUserStore } from '@/store/modules/user'
import {getNodeTypeIcon, resolveNodeId} from '@/utils/gps/device'
import {Camera, Device, Group, Company} from '@/interface/home'
import { Storage } from '@/utils/storage'
import useDeviceStore from '@/store/gps/device'
import Menu, {ItemName} from '@/components/menu/deviceMenu.vue'
import { storeToRefs } from 'pinia'
import {useGroupListApi, useOrgList3Api} from "@/api/sys/orgs";
import TreeNode from "@/components/tree/treeNode";
import {arrayToTree, initDictionary, insertArrayIntoTree} from "@/components/tree/tree_tools";
import {computeTreeIcon} from "@/utils/gps/iconTransform";
const deviceStore = useDeviceStore()

const searchDeviceList = ref<any[]>([])
const searchLoading = ref(false)

const userStore = useUserStore()
const treeConfiguration = ref<string[]>(Storage.getItem('treeConfiguration') || [])
const sendCmd = ref()
const deviceRef = ref<InstanceType<typeof ElTree>>()
const deviceList = shallowRef<Device[]>([])
//是否全选
const checkAll = ref<boolean>(false)
const isIndeterminate = ref<boolean>(false)

// 已选中设备集合; 是否需要渲染摄像头; 当前选中的机构
const { checkedDeviceList, video, checkedDeviceNodeId, videoPageDisable } = storeToRefs(deviceStore)

// 已选中的摄像头列表 {type + id + channel: data}
const checkedCameraList = ref<{[nodeId: Camera["nodeId"]]: Camera}>({})

// 获取已选中的设备nodeId列表
const checkedDeviceKeys = computed(() => {
  return Object.keys(checkedDeviceList.value)
})
// 获取已选中的摄像头nodeId列表
const checkedCameraKeys = computed(() => {
  return Object.keys(checkedCameraList.value)
})
// 获取设备和摄像头的总和列表
const checkedCameraAndDeviceKeys = computed(() => {
  return checkedDeviceKeys.value.concat(checkedCameraKeys.value)
})
// 获取已选中的设备数
const getCheckedDeviceCount = computed(() => {
  return Object.keys(checkedDeviceList.value).length
})

const checkedCities = ref<any[]>([])

const deviceListLoading = ref(false)

// const dropdown = ref()
const queryForm = reactive({
  connectionStatus: 'total',
  orderField: 'signal_update_time',
  onlyVideo: false,
  order: 'DESC',
  keyWords: '',
  pageNum: 1,
  pageSize: 1000
})

const searchKey = ref('')

const deviceStatusOptions = [
  { label: '全部', value: 'total' },
  { label: '在线', value: 'online' },
  { label: '离线', value: 'offline' },
  { label: '关注', value: 'favor' }
]
const deviceStatusAll = ref({
  total: 0,
  online: 0,
  offline: 0,
  favor: 0
})

watch(
  () => queryForm.connectionStatus,
  () => {
    checkAll.value = false
    deviceRef.value?.setCheckedKeys([])
  }
)
watch(
  () => treeConfiguration.value,
  (value) => {
    Storage.setItem('treeConfiguration', value)
  }
)

/**
 * checkedDeviceChannelAll: DeviceList组件内部方法 用于选中所有设备的子项
 * deselect: DeviceList组件内部方法 用于删除某一个设备的选中
 */
onMounted(() => {
  gpsbus.on('WS_CMD_POSITIONS', positionsCome)
  gpsbus.on('checkedDeviceChannelAll', checkedDeviceChannelAll)
  gpsbus.on('unSelect', deselect)
  gpsbus.on('deviceSetRow', deviceSetRow)
  getDeviceStatusInfo()
  initializeInstitutionsAndGroups()
})
onUnmounted(() => {
  gpsbus.off('WS_CMD_POSITIONS', positionsCome)
  gpsbus.off('checkedDeviceChannelAll', checkedDeviceChannelAll)
  gpsbus.off('unSelect', deselect)
  gpsbus.off('deviceSetRow', deviceSetRow)
  deviceStore.clearState()
})

const treeData = ref<any[]>([])
let deviceDict: { [key: string]: string }
let deviceNodeGroup: { [key: string]: string[] }
/**
 * 初始化机构和组别
 */
function initializeInstitutionsAndGroups(){
  deviceListLoading.value = true
  Promise.all([useOrgList3Api({onlyVideo: queryForm.onlyVideo}), useGroupListApi(), useDeviceListApi(cloneDeep(queryForm))]).then(res =>{
    const institutions: Company[] = arrayToTree(res[0].data.map(item => {
      return {
        nodeType: "company",
        name: item.name,
        id: item.id,
        nodeId: "i-" + item.id,
        parentId: item.pid,
        totalDeviceNum: item.totalDeviceNum,
        onlineDeviceNum: item.onlineDeviceNum,
        totalDeviceOnlineNum: item.totalDeviceOnlineNum,
        deviceOnlineNum: item.deviceOnlineNum,
        children: []
      }
    }), "company", userStore.user.orgId), groups: Group[] = arrayToTree(res[1].data.map(item =>{
      return {
        nodeType: "group",
        name: item.name,
        deptId: item.deptId,
        id: item.id,
        nodeId: "g-" + item.id,
        parentId: item.parentId,
        totalDeviceNum: item.totalDeviceNum,
        onlineDeviceNum: item.onlineDeviceNum,
        children: []
      }
    }), "group"), device: Device[] = res[2].data.list?.map(item => {
      return {
        nodeType: "device",
        nodeId: "d-" + item.imei,
        address: item.address,
        direction: item.direction,
        companyId: item.companyId,
        connectionStatus: item.connectionStatus,
        icon: item.icon,
        groupId: item.groupId,
        imei: item.imei,
        alarms: item.alarms,
        jt1078Avch: item.jt1078Avch,
        jt1078Avset: item.jt1078Avset,
        latitude: item.latitude,
        longitude: item.longitude,
        plateNo: item.plateNo,
        platformStartDate: item.platformStartDate,
        positionUpdateTime: item.positionUpdateTime,
        signalUpdateTime: item.signalUpdateTime,
        speed: item.speed,
        subTitle: item.subTitle,
        todayDistance: item.todayDistance,
        totalDistance: item.totalDistance,
        attribute: item.attribute
      }
    })
    // 合并公司和组别
    insertArrayIntoTree(institutions, groups)
    // 存储全部设备
    deviceList.value = device
    treeData.value = institutions
     setTimeout(()=>{
       // 添加设备节点
       initializeTheDeviceNode(device)
       InitializeChildNodesForNodes(device)
     }, 1000)

    // 初始化设备字典
    const { deviceNodeIdGroup, deviceGroupDict } = initDictionary(institutions, device)
    deviceNodeGroup = deviceNodeIdGroup
    deviceDict = deviceGroupDict


    console.log(deviceNodeGroup)
    setTimeout(()=>{
      deviceListLoading.value = false
    }, 1000)
  })
}

/**
 * 获取全部设备状态
 */
function getDeviceStatusInfo() {
  useDeviceStatusInfoApi({
    onlyVideo: queryForm.onlyVideo
  }).then((res) => (deviceStatusAll.value = res.data))
}


/**
 * 获取设备列表及状态
 */
function init() {
  if(checkedCities.value.length > 0){
    for (let valueKey in checkedDeviceList.value) {
      handleCheckChange(checkedDeviceList.value[valueKey], false)
    }
    for (let valueKey in checkedCameraList.value) {
      handleCheckChange(checkedCameraList.value[valueKey], false)
    }
  }
  getDeviceStatusInfo()
  initializeInstitutionsAndGroups()
}

/**
 * 初始化设备节点
 */
function initializeTheDeviceNode(data: Device[]){
  data.forEach((item) => {
    if(item.groupId){
      deviceRef.value?.append(item, "g-" + item.groupId)
    }else {
      deviceRef.value?.append(item, "i-" + item.companyId)
    }
  })

}

/**
 * 初始化设备的子节点
 * @constructor
 */
function InitializeChildNodesForNodes(data: Device[]) {
  data.forEach((item) => {
    const channelNames = jt1078AvsetAnalysis(item.jt1078Avch, item.jt1078Avset)
    if (channelNames.length === 0) {
      return
    }
    for (let i = 0; i < channelNames.length; i++) {
      let cl = channelNames[i]
      deviceRef.value?.append(
        {
          nodeId: `c-${item.imei}-${i + 1}`,
          parentNodeId: item.nodeId,
          plateNoName: item.plateNo,
          plateNo: cl.name,
          channel: cl.channel,
          nodeType: 'camera',
          index: -1
        },
        item.nodeId
      )
    }
  })
}

function handleCheckedCitiesChange(value: string[]){
  const checkedCount = value.length
  checkAll.value = checkedCount === deviceList.value.length
  isIndeterminate.value = checkedCount > 0 && checkedCount < deviceList.value.length
}

/**
 * 全选按钮
 * @param val
 */
const handleCheckAllChange = (val: boolean) => {
  checkedCities.value =
    val ? deviceList.value.map((item) => {
      handleCheckChange(item, true)
      return item.nodeId
    }).concat(checkedCameraKeys.value as any) : (()=> {
      deviceList.value.forEach((item)=> handleCheckChange(item, false))
      return checkedCameraKeys.value
    })()
  isIndeterminate.value = false
}

/**
 * 行点击
 * @param data
 */
function handleNodeClick(data: Device | Group | Company | Camera) {
  console.log(data)
  const nodeId = data.nodeId
  switch (data.nodeType) {
    case "camera":
      if (!checkedCameraKeys.value.includes(nodeId)) {
        checkedCities.value.push(nodeId)
      }
      !checkedCameraList.value.hasOwnProperty(nodeId) && (checkedCameraList.value[nodeId] = data)
      break
    case "device":
      if (!checkedDeviceKeys.value.includes(nodeId)) {
        const arr = data.children?.map(item => {
          handleCheckChange(item, true)
          return item.nodeId
        }) || []
        arr.push(nodeId)
        checkedCities.value.push(...arr)
        checkedDeviceList.value[nodeId] = data
        handleCheckChange(data, true)
      }
      checkedDeviceNodeId.value = nodeId
      // 发事件出去
      gpsbus.emit('popup', nodeId)
      break
    case "group":
      break
    case "company":
      break
    default:
      break
  }
}
let timer
let arr: any[] = []
/**
 * 单选按钮
 * insertVideo: RealTimeVideo组件内部方法 用于创建一个新的的视频连接
 * @param data
 * @param checked
 */
function handleCheckChange(data: Device | Group | Company | Camera, checked: boolean) {
  const nodeId = data.nodeId
  switch (data.nodeType) {
    case "camera":
      if (checked) {
        checkedCameraList.value[nodeId] = data
        gpsbus.emit('insertVideo', data)
      } else {
        delete checkedCameraList.value[nodeId]
        gpsbus.emit('removeVideo', nodeId)
      }
      break
    case "device":
      if (checked) {
        checkedDeviceList.value[nodeId] = data
        arr.push(data)
        if (!timer) {
          timer = setTimeout(() => {
            gpsbus.emit('select', arr)
            timer = null
            arr = []
          }, 100)
        }
      } else {
        delete checkedDeviceList.value[nodeId]
        gpsbus.emit('unSelect', nodeId)
      }
      break
    case "group":
      break
    case "company":
      break
    default:
      break
  }

  checkAll.value = getCheckedDeviceCount.value === deviceList.value.length
  isIndeterminate.value = getCheckedDeviceCount.value > 0 && getCheckedDeviceCount.value < deviceList.value.length
}
/**
 * 当前选中行发生改变时触发
 * @param data
 * @param node
 */
function handelCurrentChange(data, node) {
  console.log(data,node)
  // handleNodeClick(data)
}

/**
 * 设置选中行
 * @param nodeId
 */
function deviceSetRow(nodeId: string) {
  deviceRef.value?.setCurrentKey(nodeId, true)
}

/**
 * 取消摄像头的选中
 * @param key
 */
function deselect(key: string) {
  deviceRef.value?.setChecked(key, false, false)
}

/**
 * 显示/隐藏下拉菜单
 * @param value
 * @param id
 */
function handleVisibleChange(value, id) {
  // handleRowCheckedChange(id)
}

/**
 * 子级菜单点击回调
 * @param e
 */
function commandClick(e) {
  // switch (e) {
  //   case 'DeviceTravel':
  //     createPopup(deviceRef.value.getCurrentKey())
  //     break
  //   case 'DeviceSendCmd':
  //     sendCmd.value.init(deviceRef.value.getCurrentKey())
  //     break
  // }
}

/**
 * 选中当前选中设备的子级项
 */
function checkedDeviceChannelAll(nodeId: string) {
  const device = checkedDeviceList.value[nodeId]
  if (!device) {
    return
  }
  const channelNames = jt1078AvsetAnalysis(device.jt1078Avch, device.jt1078Avset)
  if (channelNames.length === 0) {
    return
  }

  const arr = [] as string[]
  for (let i = 0; i < channelNames.length; i++) {
    let cl = channelNames[i]
    let key = `${resolveNodeId(nodeId).id}-${cl.channel}`
    if (!checkedCameraKeys.value.includes(key)) {
      arr.push(key)
    }
    // setTimeout(() => {
    //   let a = checkedDeviceKeys.value.concat(checkedCameraKeys.value, [`${imei}-${cl.channel}`])
    //   deviceRef.value?.setCheckedKeys(a)
    // }, 10)
  }
  // data.children && arr.push(...data.children.map((item) => item.imei))
  nextTick(() => {
    deviceRef.value?.setCheckedKeys(checkedCameraAndDeviceKeys.value.concat(arr))
  })
}

/**
 * 数据更新
 * @param data
 */
function positionsCome(data) {
  if(deviceListLoading.value) return
  const { position: {latitude, longitude, attributes, deviceTime, serverTime, speed, course,
    connectionStatus, alarms, address, gotsrc, accuracy}, imei } = data
  const deviceInfo = {
    latitude,
    longitude,
    attribute: attributes,
    positionUpdateTime: deviceTime,
    signalUpdateTime: serverTime,
    speed,
    direction: course,
    connectionStatus,
    alarms,
    address,
    gotsrc,
    accuracy,
    imei,
  }
  const indexStr = deviceDict[imei]
  if(indexStr){
    const index = indexStr.split("-")
    deepSearch(treeData.value, 0)
    function deepSearch(child, y){
      if(y >= index.length - 1){
        Object.assign(child[parseInt(index[y])], deviceInfo)
        return
      }
      deepSearch(child[parseInt(index[y])].children, ++y)
    }
  }
}

/**
 * 搜索回调
 * @param value
 */
function searchChange(value) {
  console.log(value)
  if (!value) {
    return
  }
  deviceSetRow("d-" + value)
}

/**
 * 获取树形组件的配置属性
 * @param key
 */
function getTreeConfig(key: string): boolean {
  return treeConfiguration.value.includes(key)
}

/**
 * 折叠按钮
 */
function foldHandle() {
  const nav = document.querySelector('#home_nav')
  nav?.classList.add('fold')
}

/**
 * 远程搜索
 */
function remoteSearchMethod(val: string) {
  if (val && val.length >= 2) {
    searchLoading.value = true
    const queryForm1 = {
      deptId: null,
      connectionStatus: 'total',
      onlyVideo: queryForm.onlyVideo,
      keyWords: val,
      orderField: 'signal_update_time',
      order: 'DESC',
      pageNum: 1,
      pageSize: 1000
    }
    useDeviceListApi(queryForm1)
      .then((res) => {
        searchDeviceList.value = res.data.list
      })
      .finally(() => (searchLoading.value = false))
  } else {
    searchDeviceList.value = []
  }
}

/**
 * 鼠标右键事件
 * @param event
 */
function rightClickEvents(event: any) {
  const el = event.target
  if (el!.className === 'custom-tree-node') {
    let menuGroups: ItemName[] = []
    switch (el.getAttribute('data-types')){
      case "device":
        menuGroups = ["trajectory", "tracking", "deviceInfo", "instructions"]
        break
      case "camera":
        return
        // break
      case "group":
        return;
        // break
      case "company":
        menuGroups = ["accountInfo", "select", "selectDeep"]
        break
    }
    render(
        h(Menu, {
          style: `left: ${event.clientX}px; top: ${event.clientY}px`,
          imei: el.getAttribute('data-imei'),
          menuGroups
        }),
        document.body
    )
    document.addEventListener('click', callback)
    function callback(event: any) {
      const menu = document.getElementById('right_click_menu')
      if (menu) {
        render(null, document.body)
      }
      document.removeEventListener('click', callback)
    }
  }
}

function modeChange() {
  videoPageDisable.value = !queryForm.onlyVideo
  init()
}

// function changeColor(data) {
//   console.log(data)
//   if(!data) return
//   if (data.type == 'camera') {
//     return
//   }
//   let color
//   data.alarms && data.alarms.length > 0
//     ? (color = 'red')
//     : data.plateNo === null && data.plateNo === ''
//       ? (color = 'black')
//       : data.devAttribute.longTimeNoTask === 'true'
//         ? (color = 'purple')
//         : (color = 'green')
//   return color
// }



</script>

<template>
  <div style="height: calc(100% - 54px)">
    <div class="search">
      <div class="control">
        <el-switch
            v-model="queryForm.onlyVideo"
            @change="modeChange"
            active-text="仅看有视频的设备"
        />
        <el-tooltip effect="light" content="刷新设备列表" placement="top">
          <el-button circle class="refresh" @click="init">
            <el-icon>
              <Refresh></Refresh>
            </el-icon>
          </el-button>
        </el-tooltip>
        <el-dropdown trigger="hover" :hide-on-click="false">
          <el-button circle>
            <el-tooltip effect="light" content="请在修改此配置后刷新网页" placement="top">
              <el-icon>
                <Setting />
              </el-icon>
            </el-tooltip>
          </el-button>
          <template #dropdown>
            <el-dropdown-menu>
              <el-checkbox-group v-model="treeConfiguration">
                <el-dropdown-item>
                  <el-tooltip
                    effect="light"
                    content="在显示复选框的情况下，是否严格的遵循父子互相关联的做法"
                    placement="right">
                    <el-checkbox label="遵循父子关联" value="check-strictly"></el-checkbox>
                  </el-tooltip>
                </el-dropdown-item>
                <el-dropdown-item>
                  <el-tooltip
                    effect="light"
                    content="是否在点击节点的时候展开或者收缩节点，如果为不选，
                      则只有点箭头图标的时候才会展开或者收缩节点"
                    placement="right">
                    <el-checkbox label="遵循父子展开" value="expand-on-click-node"></el-checkbox>
                  </el-tooltip>
                </el-dropdown-item>
                <el-dropdown-item>
                  <el-tooltip effect="light" content="是否默认展开所有节点" placement="right">
                    <el-checkbox label="默认展开全部" value="default-expand-all"></el-checkbox>
                  </el-tooltip>
                </el-dropdown-item>
                <el-dropdown-item>
                  <el-tooltip effect="light" content="是否每次只打开一个同级树节点展开" placement="right">
                    <el-checkbox label="手风琴模式" value="accordion"></el-checkbox>
                  </el-tooltip>
                </el-dropdown-item>
              </el-checkbox-group>
            </el-dropdown-menu>
          </template>
        </el-dropdown>
        <el-tooltip effect="light" content="折叠" placement="top">
          <el-button circle style="margin-left: 12px" @click="foldHandle">
            <el-icon><Fold /></el-icon>
          </el-button>
        </el-tooltip>
      </div>
      <div style="display: flex; margin-top: 10px">
        <el-select
          v-model="searchKey"
          placeholder="搜索"
          filterable
          clearable
          remote
          :remote-method="remoteSearchMethod"
          :loading="searchLoading"
          @change="searchChange">
          <el-option v-for="item in searchDeviceList" :key="item.imei" :label="item.plateNo" :value="item.imei">
            <img :src="computeTreeIcon(item)" alt="设备" class="tree-icon"></img>
            <span>{{ item.plateNo }}</span>
            <span style="margin-left: 15px">{{ computeSubTitle(item) }}</span>
          </el-option>
        </el-select>
      </div>
    </div>
    <div class="nav_tabs">
      <div class="checked_all nav_tab_item">
        <el-checkbox
          v-model="checkAll"
          :indeterminate="isIndeterminate"
          @change="handleCheckAllChange"></el-checkbox>
      </div>
      <el-segmented
        v-model="queryForm.connectionStatus"
        :options="deviceStatusOptions"
        class="nav_segmented"
        @change="init">
        <template #default="{ item }">
          {{ `${item.label}(${deviceStatusAll[item.value]})` }}
        </template>
      </el-segmented>
    </div>
    <div v-loading="deviceListLoading" class="list_tree">
      <el-scrollbar>
        <el-checkbox-group
            v-model="checkedCities"
            @change="handleCheckedCitiesChange">
          <el-tree
              ref="deviceRef"
              :data="treeData"
              :props="{
            label: 'plateNo',
            children: 'children'
          }"
              node-key="nodeId"
              :render-after-expand="false"
              :expand-on-click-node="false"
              highlight-current
              @check-change="handleCheckChange"
              @node-click="handleNodeClick"
              @node-contextmenu="rightClickEvents"
              @current-change="handelCurrentChange">
            <template #default="{ node, data }">
              <TreeNode :data="data" @checkboxEvents="handleCheckChange"></TreeNode>
            </template>
          </el-tree>
        </el-checkbox-group>
      </el-scrollbar>
    </div>
  </div>
</template>

<style scoped lang="css">
.list_tree {
  height: calc(100% - 132px);
}
.authority {
  width: 200px;
  margin-bottom: 15px;
}
.control {
  display: flex;
}
.refresh {
  margin: 0 12px;
}
.nav_tabs {
  display: flex;
  margin: 10px 0;
}
.nav_segmented {
  flex: 1;
}
.nav_tab_item {
  flex: 1;
  margin: 0 1px;
  background-color: rgb(246, 246, 246);
  padding: 3px 0;
  text-align: center;
}
.checked_all {
  max-width: 35px;
}
.zTree li {
  display: flex;
  align-items: center;
  position: relative;
}
.zTree li .zTree_dropdown {
  opacity: 0;
}
.zTree li:hover {
  background-color: rgb(245, 247, 250);
  cursor: pointer;
}
.zTree li:hover .zTree_dropdown {
  opacity: 1;
}
.zTree_icon {
  margin-right: 2px;
  vertical-align: top;
  line-height: 0;
  width: 16px;
  height: 16px;
  display: inline-block;
  border: 0 none;
  cursor: pointer;
  outline: none;
}
.zTree_content {
  display: inline-block;
  height: 100%;
  flex: 1;
}
.zTree_content span {
  font-size: 14px;
  display: inline-block;
  line-height: normal;
  transform: translateY(2px);
}

.zTree_icon2 {
  margin-right: 2px;
  vertical-align: center;
  line-height: 0;
  width: 16px;
  height: 16px;
  display: inline-block;
  border: 0 none;
  cursor: pointer;
  outline: none;
  transform: translateY(2px);
}

.on {
  background-color: antiquewhite !important;
}


</style>
